package com.service.socket.process;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.jboss.netty.channel.Channel;

import com.service.bean.JobFlow;
import com.service.bean.JobLocker;
import com.service.bean.device.Vehicle;
import com.service.bean.garbage.GarbageDataSync;
import com.service.bean.other.FrameResult;
import com.service.bean.other.VehicleScalar;
import com.service.cache.CacheManager;
import com.service.calculate.vehicle.GarbageProcessPool;
import com.service.db.impl.DbGarbage;
import com.service.garbage.GarbageUtil;
import com.service.other.Logger;
import com.service.socket.protocol.Conversion;
import com.service.socket.protocol.Packet;

/**
 * 垃圾称重协议
 * @author zyf
 *
 */
public class R_Class_FF extends R_Class_Abstract {
	public R_Class_FF(Channel channel, Packet packet) {
		super(channel, packet);
		this.vehicle = CacheManager.instance().getVehicle(packet.getDeviceNo());
	}

	public void execute() {
		try{			
			int cmdWord = Integer.parseInt(this.packet.cmdWord, 16);
			switch (cmdWord) {
			case 0:
				method_00();
				break;			
			case 1:
				method_01();
				break;
			case 3:
				method_03();
				break;
			case 5:
				method_05();
			}
		}catch(Exception e){
			Logger.err(e);
		}		
	}

	private void method_00() {		
		System.out.println("");
		System.out.println("服务器下发同步指令start " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		String msg = GarbageUtil.toStringHex(this.packet.dataArea);
		if (msg.equals(""))
			return;
		String[] arr = msg.split(",");
		String companyCode = arr[0];
		String typeNo = arr[1];
		//获得所有的车
		for(Vehicle vehicle:CacheManager.instance().vehicleMap.values()){
			if(vehicle.company.code.equals(companyCode)){
				FrameResult frameResult = DbGarbage.getFrameCount(vehicle.company, vehicle.device.deviceNo, typeNo);
				if(frameResult.getSize()>0){
					//添加一个任务
					addjob_FF02(vehicle.device.deviceNo,typeNo);
					//执行任务（串行化）				
					dojob_FF02(vehicle.device.deviceNo,typeNo);	
				}
			}
		}
	}
	
	/**
	 * 终端主动发送垃圾称重数据
	 */
	public void method_01() {
		if (this.vehicle == null) {
			this.packet.status = "01";
			this.packet.dataArea = null;
			SendCommand.replyDtu(this.channel, this.packet);
			Logger.err("device [" + this.packet.getDeviceNo()+ "] vehicle no band");
			return;
		}
		if (!(this.packet.isCrcValid())) {
			this.packet.status = "01";
			this.packet.dataArea = null;
			SendCommand.replyDtu(this.channel, this.packet);
			Logger.err("device [" + this.packet.getDeviceNo()+ "] regist fail on [isCrcValid]:"+ this.packet.isCrcValid());
			return;
		}
		//一辆车一个对应的bean
		if(!CacheManager.instance().scalarCalers.containsKey(packet.getDeviceNo())){
			CacheManager.instance().scalarCalers.put(packet.getDeviceNo(), new VehicleScalar());
		}
		
		VehicleScalar vehicleScalar = CacheManager.instance().scalarCalers.get(packet.getDeviceNo());	
		
		Packet bean = (Packet) this.packet.clone();
		bean.status = "00";
		bean.dataArea = null;
		SendCommand.replyDtu(this.channel, bean);
		CacheManager.instance().getGarbageDataSaveQueue(packet.getDeviceNo()).offer(packet);	
		GarbageProcessPool.scalarCal(vehicleScalar, packet.getDeviceNo());
	}	

	/**
	 * 追加一个下发任务
	 * @param gpsNo
	 * @param typeNo
	 */
	public static void addjob_FF02(String gpsNo,String typeNo) {
		Vehicle vehicle = CacheManager.instance().getVehicle(gpsNo);
		if(vehicle == null){
			//gps的车不存在，什么都不干
//			System.out.println("车不存在，追加取消");
			return;
		}
		
		if(!vehicle.sensorMap.containsKey("110")){
			//没有称重传感器
//			System.out.println("没有传感器");
			return;
		}
		
		if(!CacheManager.instance().sessionMap.containsKey(gpsNo)){
			//车不在线，什么都不干
//			System.out.println("车不在线，追加取消");
			return;
		}
		
		//一辆车一个对应的bean
		if(!CacheManager.instance().jobLockerMap.containsKey(gpsNo)){
			CacheManager.instance().jobLockerMap.put(gpsNo, new JobLocker(new Date()));
		}	
		JobLocker jobLocker = CacheManager.instance().jobLockerMap.get(gpsNo);
		
		//这里必须加个同步锁
		synchronized (jobLocker) {	
			if(CacheManager.instance().jobFlowMap.containsKey(gpsNo)){
				//这个是头
				JobFlow headjobFlow =  CacheManager.instance().jobFlowMap.get(gpsNo);
				//找到尾巴
				JobFlow tailjobFlow = JobFlow.tailJob(headjobFlow);
				//放到尾巴上
				tailjobFlow.nextJob = new JobFlow(gpsNo,typeNo);
				System.out.println("增加了一个nextJob");
				return;
			}else{
				//放到头部
				JobFlow headJob = new JobFlow(gpsNo,typeNo);
				CacheManager.instance().jobFlowMap.put(gpsNo, headJob);	
				return;
			}
		}
	}
	
	/**
	 * 执行一个任务 被5个地方调用,而且处理比较慢，采用GPS对象锁和责任链模式
	 * @param gpsNo
	 * @param typeNo
	 */
	public static void dojob_FF02(String gpsNo,String typeNo) {
		//一辆车一个对应的bean
		if(!CacheManager.instance().jobLockerMap.containsKey(gpsNo)){
			CacheManager.instance().jobLockerMap.put(gpsNo, new JobLocker(new Date()));
		}	
		JobLocker jobLocker = CacheManager.instance().jobLockerMap.get(gpsNo);
		
		//这里必须加个同步锁 把处理锁在里面
		synchronized (jobLocker) {			
			Vehicle vehicle = CacheManager.instance().getVehicle(gpsNo);
			if(vehicle == null){
				//gps的车不存在，什么都不干
//				System.out.println("车不存在，同步取消");
				return;
			}
			
			if(!vehicle.sensorMap.containsKey("110")){
				//没有称重传感器
//				System.out.println("没有传感器");
				return;
			}
			
			if(!CacheManager.instance().sessionMap.containsKey(gpsNo)){
				//车不在线，什么都不干
//				System.out.println("车不在线，同步取消");
				return;
			}
	
			JobFlow job = CacheManager.instance().jobFlowMap.get(gpsNo);				
			if(job.StartTime == null){
				//没有上一个任务
			}else{
				if(System.currentTimeMillis() - job.StartTime.getTime() <1000*60*2){
					//上一个任务还没有超时(2分钟有效期 统计时间：最新一帧的时间) 
					Logger.err("下发同步指令取消  上一个任务尚未超时(2分钟有效期) " + " gpsNo:" + gpsNo + " typeNo:" + typeNo + " time:" + job.StartTime);
					return;
				}else{
					//上一个任务已经超时,已经坏死(重新执行上一个任务) 
					Logger.err("开始重新执行任务(旧任务超时 2分钟有效期)" + " gpsNo:" + gpsNo + " typeNo:" + typeNo + " time:" + job.StartTime);				
				}
			}
	
			//继续处理，取出需要处理的帧数
			//更新发送时的时间
			job.StartTime = new Date();		
			FrameResult frameResult = DbGarbage.getFrameCountByGpsNo(vehicle.company, gpsNo,typeNo);
			if(frameResult.getSize() == 0){
				//没记录，任务完成，走到下一个节点
				JobFlow headjobFlow =  CacheManager.instance().jobFlowMap.get(gpsNo);
				JobFlow nextJob = JobFlow.nextJob(headjobFlow);
				if(nextJob != null){
					//启动下一个job | 递归到下一个job没有为止
					System.out.println("");
					System.out.println("启动下一个job 下发同步指令start");
					dojob_FF02(nextJob.gpsno,nextJob.typeno);
					return;
				}else{
					//处理结束
					return;
				}
			}

			job.Size = frameResult.getSize();
			//开始通知终端
			StringBuilder builder = new StringBuilder();
			builder.append(typeNo);
			builder.append(Conversion.reversal(Conversion.padLeft(4,Integer.toHexString(frameResult.getSize()), '0')));
			builder.append(Conversion.checkSum(builder.toString()));
			Packet p = new Packet();
			p.cmdType = "FF";
			p.cmdWord = "02";
			p.deviceNo = Conversion.padLeft(14, gpsNo, '0');
			p.dataArea = builder.toString();
			p.status = "02";
			SendCommand.send(p);
						
			System.out.println("开始FF: " + new Date());
			System.out.println("服务器02指令：" + p.toString() + " jobLocker:" + jobLocker.hashCode());
		}
	}
	
	/**
	 * 终端请求远程信息同步帧
	 * 要一帧，给一帧
	 */
	private void method_03() {
		System.out.println("客户端03指令:" + this.packet.toString());
		if (!(this.packet.dataArea.equals(""))) {
			String typeNo = this.packet.dataArea.substring(0, 2);
			String indexStr = this.packet.dataArea.substring(2, 6);
			int index = Integer.parseInt(Conversion.reversal(indexStr), 16);
			Vehicle vehicle = CacheManager.instance().getVehicle(this.packet.getDeviceNo());
			List<GarbageDataSync> list = DbGarbage.getGarbageList(vehicle.company,vehicle.device.deviceNo, typeNo);
			if(list.size() == 0){
				//发生了预想外的情况，应该有数据缺没有，把连接切断，防止并行
				if(CacheManager.instance().sessionMap.containsKey(packet.getDeviceNo())){
					Integer channelID = CacheManager.instance().sessionMap.get(packet.getDeviceNo());			
					if (CacheManager.instance().activeChannel.containsKey(channelID)) {
						CacheManager.instance().activeChannel.get(channelID).close();
					}
				}		
				System.out.println("服务器端04指令取消，连接切断");
				return;
			}
			
			
			GarbageDataSync data = list.get(index);
			StringBuilder builder = new StringBuilder();
			builder.append(typeNo);
			builder.append(indexStr);
			builder.append(Conversion.padLeft(2, data.OprStatus, '0'));
			builder.append(Conversion.utfToHexString(data.ParaData1) + "00");
			builder.append(Conversion.utfToHexString(data.ParaData2) + "00");
			if (typeNo.equals("03")) {
				if(data.ParaData3 == null){
					builder.append(Conversion.utfToHexString("") + "00");
				}else{
					builder.append(Conversion.utfToHexString(data.ParaData3) + "00");
				}
				if(data.ParaData4 == null){
					builder.append(Conversion.utfToHexString("") + "00");
				}else{
					builder.append(Conversion.utfToHexString(data.ParaData4) + "00");
				}
				if(data.ParaData5 == null){
					builder.append(Conversion.padLeft(2, "", '0'));
				}else{
					builder.append(Conversion.padLeft(2, data.ParaData5, '0'));
				}
			}
			builder.append(Conversion.checkSum(builder.toString()));
			this.packet.cmdType = "FF";
			this.packet.cmdWord = "04";
			this.packet.dataArea = builder.toString();
			this.packet.status = "02";
			SendCommand.send(this.packet);
			//把和终端交互的最新时间刷新一下
			JobFlow job = CacheManager.instance().jobFlowMap.get(packet.getDeviceNo());	
			//更新发送时的时间
			job.StartTime = new Date();
			System.out.println("服务器端04指令:" + this.packet.toString() + " OprStatus:" + data.OprStatus + " ParaData1:" + data.ParaData1 + " ParaData2:" + data.ParaData2 + " ParaData3:" + data.ParaData3 + " ParaData4:" + data.ParaData4);
		}
	}

	/**
	 * 终端回复全部数据接收并存储成功
	 * 结束指令
	 */
	private void method_05() {
		System.out.println("客户端05命令:" + this.packet.toString());
		if (!(this.packet.dataArea.equals(""))) {
			String typeNo = this.packet.dataArea.substring(0, 2);
			Vehicle vehicle = CacheManager.instance().getVehicle(this.packet.getDeviceNo());
			JobFlow headjobFlow =  CacheManager.instance().jobFlowMap.get(this.packet.getDeviceNo());
			
			List<GarbageDataSync> list = DbGarbage.getGarbageList(vehicle.company,this.packet.getDeviceNo(), typeNo);
			if(headjobFlow.Size>list.size()){
				//万一数据被人为修改,防止下标溢出
				headjobFlow.Size = list.size();
			}
			//只删除这一波数据
			for (int i = 0;i<headjobFlow.Size;i++) {
				GarbageDataSync data =list.get(i);
				DbGarbage.deleteCollectionDataById(data.id, vehicle.company);
			}
			this.packet.status = "00";
			SendCommand.send(this.packet);
			System.out.println("服务器05指令：" + this.packet.toString());
			System.out.println("执行结束！！！！！！！！！！！！！！！！");
			
			JobFlow nextJob = JobFlow.nextJob(headjobFlow);
			if(nextJob != null){
				//启动下一个job
				System.out.println("");
				System.out.println("启动下一个job 下发同步指令start");
				dojob_FF02(nextJob.gpsno,nextJob.typeno);
			}			
		}
	}
	

}